package com.hyw.trace.utils;

import java.lang.reflect.Modifier;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.util.Assert;

/**
 * 用于内部自己管理缓存的类与类实例
 * 
 * @author hongyu
 */
public abstract class InstanceFactory {
  private static Map<Class<?>, Object> INSTANCE_CACHES = new ConcurrentHashMap<>();
  private static Map<Class<?>, Class<?>> GENERIC_TYPE_CACHES = new ConcurrentHashMap<>();

  /**
   * 基于默认构造函数的对象创建
   * 
   * @param <T>
   *          泛型产出类
   * @param clz
   *          目标类型
   * @return 返回默认构造函数的实例
   */
  public static <T> T getInstance(Class<T> clz) {
    return getInstance(clz, null, null);
  }

  /**
   * 基于带参构造函数的对象创建
   * 
   * @param <T>
   *          泛型产出类
   * @param clz
   *          目标类型
   * @param argClz
   *          入参类型
   * @param argValue
   *          入参的实际值
   * @return 返回参数构造后的实例对象
   */
  @SuppressWarnings("unchecked")
  public static <T> T getInstance(Class<T> clz, Class<?> argClz, Object argValue) {
    Objects.requireNonNull(clz);
    return (T) INSTANCE_CACHES.computeIfAbsent(clz, k -> {
      Object instance = null;
      if (Objects.isNull(argClz) && Objects.isNull(argValue)) {
        instance = ReflectionUtils.newInstanceOf(clz);
      } else {
        instance = ReflectionUtils.newInstanceOf(clz, argClz, argValue);
      }
      return instance;
    });
  }

  /**
   * @param clz
   *          当前查询的子类
   * @param baseClass
   *          对应于clz的最高层的抽象类,不支持接口, 因为接口无法保存泛型信息
   * @return 找到的clz或者其子类
   */
  public static Class<?> getGenericType(Class<?> clz, Class<?> baseClass) {
    Objects.requireNonNull(clz);
    Objects.requireNonNull(baseClass);
    Assert.isTrue(!baseClass.isInterface() && Modifier.isAbstract(baseClass.getModifiers()), "baseClass 必须是抽象类");

    return GENERIC_TYPE_CACHES.computeIfAbsent(clz, k -> {
      Class<?> z = ReflectionUtils.getClass(clz.getGenericSuperclass(), 0);
      while (z != baseClass && baseClass.isAssignableFrom(z) && z != Object.class) {
        z = ReflectionUtils.getClass(z.getGenericSuperclass(), 0);
      }
      return z;
    });

  }

  /**
   * 用于获取类泛型化时的具体类型,如果泛型是体现于接口的, 那就永远是返回Object.
   * <p>
   * 同时, 由于类继承机制的原因, 该方法只会查询当前子类的上一级父类.不会自动查询整个继承树. 如果需要对继承树进行上行查找,则使用{@link #getGenericType(Class, Class)}
   * 
   * @param clz
   *          传入的泛型类对象
   * @return clz的具体泛型类型
   */
  public static Class<?> getGenericType(Class<?> clz) {
    Objects.requireNonNull(clz);
    return GENERIC_TYPE_CACHES.computeIfAbsent(clz, k -> {
      return ReflectionUtils.getClass(clz.getGenericSuperclass(), 0);
    });
  }

}
